
我們可以通過 Core Animation 來對圖片做各種翻轉的操作。

當使用者在畫面上滑動的時候,根據使用者手指所在的位置來180度翻轉卡片。
當翻轉超過 90度的時候,會看得見背面那張圖片。
在 ViewController 中建立一個繼承於 CALayer 的 cardLayer 並放在 view.layer 上
在 cardLayer 上我們會先放上一張圖片 ( img-card )
後面會提到為什麼要改變 anchorPoint.
let screen                       = UIScreen.main.bounds
let cardImage                    = UIImage(named: "img-card")!
let cardWidth                    = screen.width * 0.5
let cardHeight                   = cardImage.size.height * (cardWidth / cardImage.size.width)
cardLayer                        = CALayer()
cardLayer.contents               = cardImage.cgImage
cardLayer.anchorPoint            = CGPoint(x: 1.0, y: 0.5)
cardLayer.frame                  = CGRect(x: 0, y: 0, width: cardWidth, height: cardHeight)
cardLayer.position               = CGPoint(x: view.frame.midX, y: view.frame.midY / 2)
view.layer.addSublayer(cardLayer)
通過 UIPanGesture 來獲取手勢在 view 上拖動的情況
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panHandler))
view.addGestureRecognizer(panGesture)
通過 panHandler 拿到 UIPanGestureRecognizer 事件以後,
我們就可以使用 sender.location(in:view) 方法知道使用者在 view 上當前的座標。
架設使用者滑動到(點到)畫面的最中央時,卡牌就要正好 90度垂直於畫面,也就是手指到最右邊的時候卡片 180度翻開。
而為了讓圖片有翻動的效果:
@objc private func panHandler(_ sender: UIPanGestureRecognizer) {
    let screen = UIScreen.main.bounds
    let point  = sender.location(in: view)
    
    // init perspective transform
    var perspectiveTransform = CATransform3DIdentity
    perspectiveTransform.m34 = -1.0 / 2000.0
    
    // roate - 將平面滑動的距離轉換成弧度
    let rate:CGFloat     = 180 / screen.width
    let angle            = point.x * rate * CGFloat(Double.pi) / 180.0
    perspectiveTransform = CATransform3DRotate(perspectiveTransform, angle, 0, 1, 0)
    CATransaction.setDisableActions(true)
    cardLayer.transform = perspectiveTransform
    
    // change image when roate over half
    cardLayer.contents = UIImage(named: point.x >= screen.width / 2.0 ? "img-tree" : "img-card")?.cgImage
    
    // when pan ended
    if sender.state == .ended {
        // init perspectiveTransform
        perspectiveTransform = CATransform3DIdentity
        perspectiveTransform.m34 = -1.0 / 2000.0
        // rotate
        let x:CGFloat = point.x >= (screen.width / 2) ? 180 : 0
        let angle     = x * CGFloat(Double.pi) / 180.0
        perspectiveTransform = CATransform3DRotate(perspectiveTransform, angle , 0, 1, 0)
        CATransaction.setDisableActions(false)
        cardLayer.transform = perspectiveTransform
    }
}
m34 默認值是 0, 我們可以通過設置 m34 為 1.0 / d 來實現透視效果,d 代表視角相機和屏幕之間的距離。
 
 
旋轉圖片的方法,通過參數就能夠同時對 x,y,z 軸旋轉指定的度數,還能做形狀變化(比如透視)
CATransform3DRotate(_ t: CATransform3D, _ angle: CGFloat, _ x: CGFloat, _ y: CGFloat, _ z: CGFloat) -> CATransform3D
AnchorPoint 用來描述圖層的相對座標,圖層左上角是 (0,0) 右下角是 (1,1)
默認狀態下 AnchorPoint 位於圖層的正中間 (0.5, 0.5)
通過圖片來解釋看看,
看到結果顯示,position 並沒有改變,但是 frame 卻移動了位置。


